<script setup>
import { nextTick, onMounted, onUnmounted } from 'vue'
import * as THREE from 'three';
// 引入Three.js扩展库
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { borderLine, updateFlyGeo, flylineFun, normalLine } from './js/line'
// import { shapeMesh } from './shapeMesh'; // 轮廓填充
import { ExtrudeMesh } from './js/extrudeMesh'
import { lishuiData, testData } from './data/lishuiData'
import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js';
import { CSS3DRenderer, CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
import { getPostion } from './js/box3'
import { exportGLTF } from './js/export'
import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils'


const scene = new THREE.Scene();
const mapGroup = new THREE.Group();
const lineGroup = new THREE.Group(); //边界线组
const meshGroup = new THREE.Group(); //轮廓Mesh组
const flyGroup = new THREE.Group(); //线与飞线组
const tagGroup = new THREE.Group(); //地图标签组
const nameGroup = new THREE.Group(); //地图名称组
// const circleGroup = new THREE.Group(); //地图圆圈组
const strudeHeight = 0.12;  //拉伸的高度
let boxCenter = null;
function disposeGroup(group) {
    // .traverse方法递归遍历group的所有后代
    group.traverse(function (obj) {
        if (obj.type == 'Mesh' || obj.type == 'Line') {
            obj.geometry.dispose();
            obj.material.dispose();
        }
    })
    if (group.children.length) {
        group.children = []; //删除所有后代模型对象
    }
}

const init = () => {
    // if (meshGroup.children.length) disposeGroup(meshGroup);
    // if (lineGroup.children.length) disposeGroup(lineGroup);

    //创建场景对象Scene
    const box = document.querySelector('#three');
    const latitude = 119.568759;
    const longitude = 28.183501;

    const loader = new THREE.FileLoader();
    loader.setResponseType('json');
    // 组对象mapGroup是所有国家边界Line模型的父对象

    scene.add(mapGroup);
    mapGroup.add(lineGroup);
    lineGroup.position.z += strudeHeight + 0.001;//适当偏移解决深度冲突
    mapGroup.add(meshGroup);
    mapGroup.add(flyGroup);
    mapGroup.add(tagGroup);
    mapGroup.add(nameGroup);
    // mapGroup.add(circleGroup);

    const hebingList = [];
    // 异步加载包含世界各个国家边界坐标的GeoJSON文件：world.json
    loader.load('./json/lishui.json', (data) => {
        // 访问所有国家边界坐标数据：data.features
        data.features.forEach((area) => {
            // "Polygon"：国家area有一个封闭轮廓
            // "MultiPolygon"：国家area有多个封闭轮廓
            if (area.geometry.type === "Polygon") {
                // 把"Polygon"和"MultiPolygon"的geometry.coordinates数据结构处理为一致
                area.geometry.coordinates = [area.geometry.coordinates];
            }
            // 解析所有封闭轮廓边界坐标area.geometry.coordinates
            lineGroup.add(borderLine(area.geometry.coordinates, box.clientWidth, box.clientHeight));//国家边界轮廓插入组对象mapGroup
            // mapGroup.add(shapeMesh(area.geometry.coordinates));//国家轮廓Mesh插入组对象mapGroup

            const geometry = ExtrudeMesh(area.geometry.coordinates, strudeHeight)

            hebingList.push(geometry)
            // meshGroup.add(mesh);//地级市轮廓拉伸Mesh插入组对象mapGroup
            // tagList(item, index)
            nameGroup.add(tagDiv(area.properties))
        });

        // 添加贴图
        const textureLoader = new THREE.TextureLoader(); // TextureLoader创建一个纹理加载器对象
        const textureMap = textureLoader.load('./json/bg2.png')
        textureMap.repeat.x = 1
        textureMap.repeat.y = 1
        textureMap.wrapS = THREE.RepeatWrapping;  //纹理水平方向的平铺方式
        textureMap.wrapT = THREE.RepeatWrapping;  //纹理垂直方向的平铺方式
        const scale = 0.5;
        textureMap.repeat.set(scale, scale);
        textureMap.offset.set(0.7, 0.5);
        const material = new THREE.MeshLambertMaterial({
            map: textureMap,
            // color:0x121268,
            transparent: true, //使用背景透明的png贴图，注意开启透明计算
            opacity: 1,
            side: THREE.DoubleSide, //双面可见
        });


        const BfferGeometry = BufferGeometryUtils.mergeBufferGeometries(hebingList);

        const allMesh = new THREE.Mesh(BfferGeometry, material);
        meshGroup.add(allMesh);
        // 地图底部边界线
        const lineGroup2 = lineGroup.clone();
        mapGroup.add(lineGroup2);
        lineGroup2.position.z = - 0.001;//适当偏移解决深度冲突

        // getPostion(lineGroup)
        mapGroup.rotateX(-Math.PI / 2);
        boxCenter = getPostion(mapGroup)

    })

    //three.js辅助坐标系
    // const axesHelper = new THREE.AxesHelper(300);
    // scene.add(axesHelper);


    //光源设置
    
    const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
    directionalLight.position.set(1,1,1)
    const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight);

    scene.add(directionalLight);
    // scene.add(directionalLightHelper);
    const point = new THREE.PointLight(0xffffff);
    // point.position.set(0, 0, 0); //点光源位置
    // scene.add(point); //点光源添加到场景中
    //环境光
    const ambient = new THREE.AmbientLight(0xffffff,0.5);
    scene.add(ambient);

    //相机设置
    const width = box.clientWidth; //窗口宽度
    const height = box.clientHeight; //窗口高度
    const k = width / height; //窗口宽高比
    const s = 0.8; //三维场景显示范围控制系数，系数越大，显示的范围越大

    //创建相机对象
    const camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
    camera.position.set(0, 40, 50); //设置相机位置
    camera.lookAt(0, 0, 0); //设置相机方向(指向的场景对象)

    //创建渲染器对象
    const renderer = new THREE.WebGLRenderer({
        antialias: true, //开启锯齿
    });


    renderer.setSize(width, height); //设置渲染区域尺寸
    renderer.setClearColor(0xb9d3ff, 0); //设置背景颜色
    box.appendChild(renderer.domElement); //元素中插入canvas对象





    // 插入标签
    lishuiData.forEach((item, index) => {
        const label = tagList(item, index)
        tagGroup.add(label)
        // const circle = circleList(item, index, 'circle')
        // circleGroup.add(circle)
        // scene.add(tagList(item, index))
    })

    // // 创建一个CSS2渲染器CSS2DRenderer
    const labelRenderer = new CSS3DRenderer();
    labelRenderer.setSize(box.clientWidth, box.clientHeight);
    labelRenderer.domElement.style.position = 'absolute';
    // 避免renderer.domElement影响HTMl标签定位，设置top为0px
    labelRenderer.domElement.style.top = '0px';
    labelRenderer.domElement.style.left = '0px';
    //设置.pointerEvents=none，以免模型标签HTML元素遮挡鼠标选择场景模型
    labelRenderer.domElement.style.pointerEvents = 'none';
    box.appendChild(labelRenderer.domElement);



    //线条模型对象

    testData.forEach(item => {
        const lineObj = normalLine(lishuiData[item.from], lishuiData[item.to], box, strudeHeight);
        flyGroup.add(lineObj);
        const list = [22, 39, 34, 60, 55, 45, 18, 23, 36];
        const randomIndex = Math.floor(8 * Math.random() + 1);
        const testFlyLine = flylineFun(list[randomIndex], lineObj.flyTrackPoints, box)
        // testFlyLine.index = Math.floor(30 * Math.random()); //索引位置随机
        lineObj.add(testFlyLine)
    })



    const render = () => {

        flyGroup.children.forEach((item, i) => {
            const points = item.flyTrackPoints;
            const flyLine = item.children[0];
            const indexMax = points.length - flyLine.num; //飞线取点索引范围
            if (flyLine.index < indexMax) flyLine.index += 1
            else flyLine.index = 0
            updateFlyGeo(flyLine, points)
        })

        // circleGroup.children.forEach(item => {
        //     // console.log('itemmmm', item);
        //     let op = item.element.style.opacity;
        //     if (op > item.opacityMin) item.element.style.opacity -= 0.01
        //     else item.element.style.opacity = item.opacityMax

        //     // let scale = item.scale;
        //     if (item.scale.x < item.scaleMax) {
        //         item.scale.x += 0.00001
        //         item.scale.y += 0.00001
        //         item.scale.z += 0.00001
        //     } else {
        //         item.scale.x = item.scaleMin
        //         item.scale.y = item.scaleMin
        //         item.scale.z = item.scaleMin
        //     }
        // })

        labelRenderer.render(scene, camera);
        renderer.render(scene, camera); //执行渲染操作
        requestAnimationFrame(render); //请求再次执行渲染函数render，渲染下一帧
    }
    render();
    const controls = new OrbitControls(camera, renderer.domElement);
    // 相机控件与.lookAt()无效( .target属性 )
    controls.target.set(0, 0, 0);
    // controls.enableDamping = true
    // controls.dampingFactor =0.01
    controls.update();//update()函数内会执行camera.lookAt(controls.target)
}

// obj name-N-E
// var circleLoader = new THREE.TextureLoader();
// var circle = circleLoader.load("./json/circle.png")
// const cityPoint =(label) => {
//     console.log('labellabel',label);
//   // MeshBasicMaterial:不受光照影响
//   var mat = new THREE.MeshBasicMaterial({
//     // color: 0xffff00,
//     color: 0xffffff,
//     map: circle,
//     transparent: true,
//     side: THREE.DoubleSide, //THREE.BackSide,
//     depthWrite: false, //是否对深度缓冲区有任何的影响
//   })
//   // 矩形平面几何体
//   // var geo = new THREE.PlaneGeometry(1.0, 1.0)
//   var geo = new THREE.PlaneGeometry(0.1, 0.1)
//   var cirMesh = new THREE.Mesh(geo, mat)
//   cirMesh.position.copy(label.position)
//   cirMesh.position.z = strudeHeight
//   console.log('cirMeshcirMesh',cirMesh);
//   return cirMesh
// }

const tagList = (obj, index, id = "tag") => {
    const rowTag = document.getElementById(`${id + index}`);
    const label = new CSS3DObject(rowTag);
    label.position.set(obj.E, obj.N - 0.008, strudeHeight + 0.03);
    label.scale.set(0.0008, 0.0008, 0.0008);

    label.rotateX(Math.PI / 2);
    rowTag.style.pointerEvents = 'none';

    return label
}
const circleList = (obj, index, id = "tag") => {
    const rowTag = document.getElementById(`${id + index}`);
    const label = new CSS3DObject(rowTag);
    label.scaleMax = 0.0016;
    label.scaleMin = 0.0006;
    label.opacityMax = 1;
    label.opacityMin = 0;

    label.position.set(obj.E, obj.N - 0.008, strudeHeight - 0.02);
    label.scale.set(label.scaleMin, label.scaleMin, label.scaleMin);
    label.element.style.opacity = 1
    rowTag.style.pointerEvents = 'none';
    // 自定义属性


    // console.log(label);

    return label
}
// const circleList = (obj, index) => {
//     const rowTag = document.getElementById(`circle${index}`);
//     const label = new CSS3DObject(rowTag);
//     label.position.set(obj.E, obj.N - 0.008, strudeHeight + 0.03);
//     label.scale.set(0.0008, 0.0008, 0.0008);
//     label.rotateX(Math.PI / 2);
//     // label.rotateY(Math.PI / 2);
//     rowTag.style.pointerEvents = 'none';
//     // debugger

//     return label
// }


const tagDiv = (obj) => {
    const div = document.createElement('div');
    div.innerHTML = obj.name;
    div.style.padding = '0.625rem 1.25rem';
    div.style.color = '#fff';
    div.style.fontSize = '3rem';
    div.style.position = 'absolute';
    // div.style.backgroundColor = 'rgba(25,25,25,0.1)';
    // div.style.borderRadius = '0.625rem'
    div.style.border = '1px solid #fff'
    const label = new CSS3DObject(div);
    label.position.set(obj.centroid[0], obj.centroid[1], strudeHeight - 0.01);
    label.scale.set(0.0008, 0.0008, 0.0008);
    div.style.pointerEvents = 'none';
    return label
}
const exportModel = () => {
    exportGLTF(mapGroup);
}
onMounted(() => {
    init();
})
onUnmounted(() => {
    if (mapGroup.children.length) disposeGroup(mapGroup);
    if (lineGroup.children.length) disposeGroup(lineGroup);
    if (meshGroup.children.length) disposeGroup(meshGroup);
    if (flyGroup.children.length) disposeGroup(flyGroup);
    if (tagGroup.children.length) disposeGroup(tagGroup);
    if (nameGroup.children.length) disposeGroup(nameGroup);
    if (circleGroup.children.length) disposeGroup(circleGroup);
})
</script>

<template>
    <div class="three_box">
        <!-- <div class="btn" @click="exportModel">1111</div> -->
        <div class="label" v-for="item, index in lishuiData" :key="index" :id="`tag${index}`">
            <span>{{ item.name }}</span>
        </div>
        <!-- <div class="circle" v-for="item, index in lishuiData" :key="index" :id="`circle${index}`"></div> -->
        <div id="three"></div>

    </div>

</template>
<style lang="scss" scoped>
.three_box {
    width: 100%;
    height: 100%;
    color: #fff;
    font-size: 3.75rem;
    box-sizing: border-box;
    padding-top: 0.625rem;
    position: relative;
    // background: url('../../../assets/img/lishui/big_bg.png') no-repeat;
    background-size: 100% 100%;

    .btn {
        width: 100px;
        height: 100px;
        position: absolute;
        z-index: 999;
        background-color: #fff;
    }

    .label {
        // width: 10rem;
        height: 7rem;
        position: absolute;
        pointer-events: none;
        font-size: 1.5rem;
        box-sizing: border-box;
        padding: 0.75rem 1.5rem 0;
        background-color: rgba($color: #000000, $alpha: .8);
        // left: 0;
        // top: 0;
        // background: url('./img/label.png') no-repeat;
        background-size: 100% 100%;

    }

    .circle {
        width: 6rem;
        height: 6rem;
        position: absolute;
        pointer-events: none;
        // font-size: 1.5rem;
        box-sizing: border-box;
        // padding: 0.75rem 1.5rem 0;
        // left: 0;
        // top: 0;
        background: url('./circle.png') no-repeat;
        background-size: 100% 100%;
        // animation: transformAnim linear .4s infinite;
    }

    // @keyframes transformAnim {
    //     from {
    //         transform: scale(0.008);
    //         opacity: 1;
    //     }
    //     to {
    //         transform: scale(0.012);
    //         opacity: 0.5;
    //     }
    // }

    #three {
        width: 100%;
        height: 100%;
    }
}

.test {
    color: #121268;
    color: #67e8ff;
    color: #259cac;
}
</style>